improvement(hubspot): OAuth-native polling trigger replacing webhook flow#4705
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview Adds new HubSpot polling implementation and selector endpoints. Introduces a Reviewed by Cursor Bugbot for commit 324741d. Configure here. |
Greptile SummaryThis PR replaces 27 individual HubSpot webhook trigger configurations with a single OAuth-native polling trigger (
Confidence Score: 5/5Safe to merge — the polling core is well-designed, the cursor and failure-recovery logic are correct, and all four new API routes follow the established auth pattern. The (timestamp, id) cursor with cursorFrozen failure gate, list-membership seed/resume path, and property-changed snapshot diff are all logically sound. The new selector API routes use the standard auth pattern correctly. The only finding is a minor placement of the count pagination parameter in a POST endpoint URL query string rather than its request body. apps/sim/app/api/tools/hubspot/lists/route.ts — the count pagination parameter may need to move from the URL query string into the POST request body. Important Files Changed
Sequence DiagramsequenceDiagram
participant Cron as Cron (every minute)
participant Poll as hubspotPollingHandler
participant HS as HubSpot CRM API
participant DB as providerConfig (DB)
participant WF as processPolledWebhookEvent
Cron->>Poll: pollWebhook(ctx)
Poll->>DB: read config (watermarkMs, lastSeenObjectId, snapshot)
alt "objectType == list_membership"
Poll->>HS: "GET /lists/{id}/memberships/join-order?after=cursor"
HS-->>Poll: results + paging.next.after
loop seed phase
Poll->>DB: update cursor, no emit
end
loop normal phase
Poll->>WF: processPolledWebhookEvent(payload)
WF-->>Poll: success/failure
end
Poll->>DB: "advance cursor only if failedCount == 0"
else search-based
alt first poll
Poll->>DB: "seed watermarkMs = now"
else subsequent poll
Poll->>HS: "POST /objects/{type}/search (GroupA OR GroupB)"
HS-->>Poll: results[]
Note over Poll: client-sort (ts ASC, id ASC), slice to maxRecords
loop each record
alt property_changed and value unchanged
Poll->>Poll: skip, update snapshot LRU
else
Poll->>WF: executeWithIdempotency
WF-->>Poll: success/throw
alt failure
Poll->>Poll: "cursorFrozen = true"
end
end
Poll->>Poll: advance cursor only if success and not frozen
end
Poll->>DB: persist watermark + snapshot
alt all failed
Poll->>DB: markWebhookFailed
else
Poll->>DB: markWebhookSuccess
end
end
end
Reviews (4): Last reviewed commit: "fix(hubspot): Map-backed property snapsh..." | Re-trigger Greptile |
… list-membership, pipeline/owner dropdowns
|
@greptile |
|
@cursor review |
…l-trigger conventions
…ot-oauth-trigger-refactor # Conflicts: # scripts/check-api-validation-contracts.ts
|
@greptile |
|
@cursor review |
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 324741d. Configure here.
Summary
hubspot_pollertrigger(timestamp, hs_object_id)cursor with id-based tiebreaker — no record loss even at same-millisecond bulk importslastmodifieddatefor contacts (HubSpot null bug onhs_lastmodifieddate),hs_lastmodifieddatefor othershubspotWebhookPollcron to helm values; removed 26 dead per-event trigger configs and the webhook provider handlerConfigurability (second commit)
propertiesandtargetPropertyNamepopulated live from the connected HubSpot account/crm/v3/lists/{listId}/memberships/join-order, watermark bymembershipTimestamp/api/tools/hubspot/{properties,lists,pipelines,owners}Type of Change
Testing
bunx vitest run lib/webhooks/ triggers/passes (61/61)Checklist